/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2022-12-04     yoyoyes      first version
 */

#include "thread_semaphore_demo2.h"

rt_uint32_t array[MAXSEM];          /* 用于存放生产的整数数组 */

static rt_uint32_t set, get;        /* 指向生产者、消费者在array数组中的读写位置 */

static rt_thread_t producer_tid = RT_NULL;
static rt_thread_t consumer_tid = RT_NULL;

struct rt_semaphore sem_lock;       /* 保护临界区资源 */
struct rt_semaphore sem_empty, sem_full;

/*
 * @brief  生产者线程入口函数，获取到空位后，产生一个数字，循环放到数组中，然后释放一个满位。
 *
 * @param  parameter 生产者线程入口函数参数
 *
 * @return None
 */
void producer_thread_entry(void *parameter)
{
    int cnt =  0;

    while(cnt < 10)
    {
        /* 获取一个空位 */
        rt_sem_take(&sem_empty, RT_WAITING_FOREVER);    /* 空位减一 */

        rt_sem_take(&sem_lock, RT_WAITING_FOREVER);     /* 上锁 */
        array[set % MAXSEM] = cnt + 1;                  /* 循环使用数组 */
        rt_kprintf("the producer generates a number: %d\n", array[set % MAXSEM]);
        set++;
        rt_sem_release(&sem_lock);                      /* 解锁 */

        /* 释放一个满位 */
        rt_sem_release(&sem_full);                      /* 满位加一 */
        cnt++;

        rt_thread_mdelay(20);
    }

    rt_kprintf("the producer exit!\n");
}

/*
 * @brief  消费者线程入口函数，获取到满位后，读取数组内容并相加，然后释放一个空位。
 *
 * @param  parameter 消费者线程入口函数参数
 *
 * @return None
 */
void consumer_thread_entry(void *parameter)
{
    rt_uint32_t sum = 0;

    while(1)
    {
        /* 获取一个满位 */
        rt_sem_take(&sem_full, RT_WAITING_FOREVER);     /* 满位减一 */

        rt_sem_take(&sem_lock, RT_WAITING_FOREVER);     /* 上锁 */
        sum += array[get % MAXSEM];                     /* 循环使用数组 */
        rt_kprintf("the consumer[%d] get a number: %d\n", (get % MAXSEM), array[get % MAXSEM]);
        get++;
        rt_sem_release(&sem_lock);                      /* 解锁 */

        /* 释放一个空位 */
        rt_sem_release(&sem_empty);                     /* 空位加一 */

        if(get == 10)
            break;

        rt_thread_mdelay(50);
    }

    rt_kprintf("the consumer sum is: %d\n", sum);
    rt_kprintf("the consumer exit!\n");
}

/*
 * @brief  生产者和消费者Demo函数
 *
 * @param  None
 *
 * @return None
 */
int thread_semaphore_demo2(void)
{
    set = 0;
    get = 0;

    /* 初始化3个信号量 */
    rt_sem_init(&sem_lock,  "lock",  1,      RT_IPC_FLAG_PRIO);
    rt_sem_init(&sem_empty, "empty", MAXSEM, RT_IPC_FLAG_PRIO);
    rt_sem_init(&sem_full,  "full",  0,      RT_IPC_FLAG_PRIO);

    /* 创建生产者线程 */
    producer_tid = rt_thread_create("producer", producer_thread_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
    if(producer_tid != RT_NULL)
    {
        rt_thread_startup(producer_tid);
    }
    else
    {
        rt_kprintf("create thread producer failed.\n");
        return -1;
    }

    /* 创建消费者线程 */
    consumer_tid = rt_thread_create("consumer", consumer_thread_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE);
    if(consumer_tid != RT_NULL)
    {
        rt_thread_startup(consumer_tid);
    }
    else
    {
        rt_kprintf("create thread consumer failed.\n");
        return -1;
    }

    return 0;
}





